package pers.jl.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pers.jl.common.MyException;
import pers.jl.dto.SetmealDto;
import pers.jl.entity.Category;
import pers.jl.entity.Setmeal;
import pers.jl.entity.SetmealDish;
import pers.jl.mapper.SetmealMapper;
import pers.jl.service.ICategoryService;
import pers.jl.service.ISetmealDishService;
import pers.jl.service.ISetmealService;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 套餐 服务实现类
 * </p>
 *
 * @author luge
 * @since 2023-04-22
 */
@Service
@Slf4j
public class SetmealServiceImpl extends ServiceImpl<SetmealMapper, Setmeal> implements ISetmealService {

    @Autowired
    @Lazy
    private ICategoryService categoryService;

    @Autowired
    private ISetmealDishService setmealDishService;

    /**
     * 分页查询，需要返回SetmealDto的分页对象，带有分类名称
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public Page<SetmealDto> getWithdCategoryName(int page, int pageSize,String name) {

        // 1. 根据查询条件，查出Setmeal的分页对象，并按更新时间降序
        Page<Setmeal> setmealPage = new Page<>(page,pageSize);
        LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 套餐名称不为空，模糊查询
        setmealLambdaQueryWrapper.like(name!=null,Setmeal::getName,name);
        // 根据更新时间降序排序
        setmealLambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);
        // 执行分页查询
        this.page(setmealPage,setmealLambdaQueryWrapper);

        // 2. 构建SetmealDto的分页对象，将套餐分页对象拷贝到SetmealDto的分页对象，除了records。
        Page<SetmealDto> setmealDtoPage = new Page<>();
        BeanUtils.copyProperties(setmealPage,setmealDtoPage,"records");

        // 3. 处理records,将每个Setmeal对象拷贝到SetmealDto，然后根据套餐的分类id查出分类名称，赋值给SetmealDto。
        List<Setmeal> records = setmealPage.getRecords();
        List<SetmealDto> setmealDtorecords = records.stream().map((item) ->{
            SetmealDto setmealDto = new SetmealDto();
            // 将每个Setmeal对象拷贝到SetmealDto
            BeanUtils.copyProperties(item, setmealDto);
            // 根据套餐分类id获取分类对象
            Category category = categoryService.getById(item.getCategoryId());
            if (category != null) {
                // 如果分类对象存在，获取分类对象的分类名称
                String categoryName = category.getName();
                // 将分类名称设置到SetmealDto对象中
                setmealDto.setCategoryName(categoryName);
            }
            return setmealDto;
        }).collect(Collectors.toList());

        // 4. 将处理后的records设置到SetmealDto的分页对象中。
        setmealDtoPage.setRecords(setmealDtorecords);

        // 5. 返回SetmealDto的分页对象。
        return setmealDtoPage;
    }

    /**
     * 同时保存套餐还有套餐与菜品的对应关系
     * @param setmealDto
     */
    @Override
    @Transactional
    public void saveWithDish(SetmealDto setmealDto) {

        // 1. 保存套餐信息
        this.save(setmealDto);
        // 2. 保存套餐和菜品的关系信息
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
        // 保存之前需要对这些关系信息添加套餐id
        setmealDishes.stream().map((item) -> {
            log.info("套餐id:"+String.valueOf(setmealDto.getId()));
            item.setSetmealId(setmealDto.getId());
            return item;
        }).collect(Collectors.toList());
        // 保存关系信息
        setmealDishService.saveBatch(setmealDishes);
    }

    /**
     * 套餐状态更改(单个或批量)
     * @param status
     * @param ids
     * @return
     */
    @Override
    public void changeManyStatus(int status, List<Long> ids) {
        // 1. 将ids中的套餐id全部更改状态，页面传递的状态值就是取反后的值，可以直接使用
        LambdaUpdateWrapper<Setmeal> setmealLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 套餐id在传来的集合里就更改
        setmealLambdaUpdateWrapper.in(Setmeal::getId,ids);
        // 更改状态
        setmealLambdaUpdateWrapper.set(Setmeal::getStatus,status);
        // 执行
        this.update(setmealLambdaUpdateWrapper);
    }

    /**
     * 套套餐删除功能(单个删除或批量删除)
     * @param ids
     */
    @Override
    @Transactional
    public void deleteWithDish(List<Long> ids) {
        // 1. 判断ids所有套餐的状态。
        LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // ids中的套餐id
        setmealLambdaQueryWrapper.in(Setmeal::getId,ids);
        // 查询启售状态的套餐数量
        setmealLambdaQueryWrapper.eq(Setmeal::getStatus,1);
        int count = this.count(setmealLambdaQueryWrapper);

        // 2. 启售状态不能删除，抛出异常。
        if (count > 0) {
            // 含有启售的套餐，不能删除，抛出异常
            throw new MyException("启售套餐无法删除。");
        }else {
        // 3. 停售状态可以删除。
            // 先删除套餐表
            this.removeByIds(ids);
            // 再删除套餐和菜品信息表
            LambdaQueryWrapper<SetmealDish> setmealDishLambdaQueryWrapper = new LambdaQueryWrapper<>();
            // 套餐和菜品信息表中套餐id在ids中的都删掉
            setmealDishLambdaQueryWrapper.in(SetmealDish::getSetmealId,ids);
            setmealDishService.remove(setmealDishLambdaQueryWrapper);
        }

    }

    /**
     * 修改套餐
     * 根据套餐id查出套餐所有信息(套餐和套餐菜品信息)，进行回显。
     * @param id
     * @return
     */
    @Override
    public SetmealDto getWithDish(Long id) {

        // 1. 获取套餐
        LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
        setmealLambdaQueryWrapper.eq(Setmeal::getId,id);
        Setmeal setmeal = this.getOne(setmealLambdaQueryWrapper);

        // 2. 获取套餐菜品
        LambdaQueryWrapper<SetmealDish> setmealDishLambdaQueryWrapper = new LambdaQueryWrapper<>();
        setmealDishLambdaQueryWrapper.eq(SetmealDish::getSetmealId,id);
        List<SetmealDish> setmealDishes = setmealDishService.list(setmealDishLambdaQueryWrapper);

        // 3. 将套餐和套餐菜品封装到套餐Dto对象中饭返回
        SetmealDto setmealDto = new SetmealDto();
        BeanUtils.copyProperties(setmeal, setmealDto);
        setmealDto.setSetmealDishes(setmealDishes);
        return setmealDto;
    }

    /**
     * 修改套餐
     * 保存修改，先更新套餐，然后删除原有套餐信息，再插入新套餐信息
     * @param setmealDto
     * @return
     */
    @Override
    public void updateWithDish(SetmealDto setmealDto) {

        // 1. 更新套餐
        this.updateById(setmealDto);

        // 2. 删除原有套餐菜品信息
        LambdaQueryWrapper<SetmealDish> setmealDishLambdaQueryWrapper = new LambdaQueryWrapper<>();
        setmealDishLambdaQueryWrapper.eq(SetmealDish::getSetmealId,setmealDto.getId());
        setmealDishService.remove(setmealDishLambdaQueryWrapper);

        // 3. 重新插入套餐菜品信息
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
        // 给套餐信息设置套餐id
        setmealDishes.stream().map((item) ->{
            item.setSetmealId(setmealDto.getId());
            return item;
        }).collect(Collectors.toList());
        setmealDishService.saveBatch(setmealDishes);
    }

    /**
     * 根据套餐分类id，查出所有套餐
     * @param setmeal
     * @return
     */
    @Override
    public List<Setmeal> listForSetmeals(Setmeal setmeal) {

        // 根据套餐分类id，查出所有套餐
        LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
        setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,setmeal.getCategoryId());
        // 套餐必须是启售状态
        setmealLambdaQueryWrapper.eq(Setmeal::getStatus,setmeal.getStatus());
        List<Setmeal> setmealList = this.list(setmealLambdaQueryWrapper);
        // 返回集合
        return setmealList;
    }

}
